/**
 * 
 */
package com.huxi.lang.type;

import java.sql.Date;
import java.sql.JDBCType;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * 自定义数据类型，数据类型不能为数组类型和Primitive类型。
 * 
 * @since 1.0
 * @version 1.0
 * @author jian.wu
 */
public interface VType<T> {

	final List<Class<?>> PRIMITIVE_NUMBER = Arrays.asList(int.class, long.class, double.class, float.class, short.class,
			byte.class);
	final List<Class<?>> PRIMITIVE_INTEGER = Arrays.asList(int.class, long.class, short.class, byte.class);
	final List<Class<?>> PRIMITIVE_DECIMAL = Arrays.asList(double.class, float.class);

	/**
	 * 数据类型名称
	 * 
	 * @return 名称，非空。
	 * @since 1.0
	 */
	String getName();

	/**
	 * 等效的内部实现类
	 * 
	 * @return 实现类，非空。
	 * @since 1.0
	 */
	Class<T> getOriginClass();

	/**
	 * 等效的JDBC类型
	 * 
	 * @return JDBC类型
	 * @since 1.0
	 */
	default JDBCType getJdbcType() {
		return null;
	}

	/**
	 * 参数值是否为合法值
	 * 
	 * @param value 参数值
	 * @return 合法值返回真，否则返回假。
	 * @since 1.0
	 */
	default boolean isLegal(T value) {
		return true;
	}

	/**
	 * 参数值是否为有效实例
	 * 
	 * @param value 参数值
	 * @return 合法实例返回真，否则返回假。
	 * @since 1.0
	 */
	default boolean isInstance(Object value) {
		return getOriginClass().isInstance(value);
	}

	/**
	 * 数据类型实现类是否原始类型
	 * 
	 * @return 原始类型返回真，否则返回假。
	 * @since 1.0
	 */
	default boolean isPrimitive() {
		return getOriginClass().isPrimitive();
	}

	/**
	 * 数据类型实现类是否数字类型
	 * 
	 * @return 数字类型返回真，否则返回假。
	 * @since 1.0
	 */
	default boolean isNumber() {
		Class<?> clazz = getOriginClass();
		if (clazz.isPrimitive()) {
			return PRIMITIVE_NUMBER.contains(clazz);
		}
		return Number.class.isAssignableFrom(clazz);
	}

	/**
	 * 数据类型实现类是否布尔类型
	 * 
	 * @return 布尔类型返回真，否则返回假。
	 * @since 1.0
	 */
	default boolean isBoolean() {
		Class<?> clazz = getOriginClass();
		return boolean.class.equals(clazz) || Boolean.class.equals(clazz);
	}

	/**
	 * 数据类型实现类是否日期类类型
	 * 
	 * @return 日期类类型返回真，否则返回假。
	 * @since 1.0
	 */
	default boolean isDate() {
		Class<?> clazz = getOriginClass();
		return Date.class.isAssignableFrom(clazz) || Instant.class == clazz || LocalDate.class == clazz
				|| LocalDateTime.class == clazz;
	}

	/**
	 * 数据类型实现类是否文本类型
	 * 
	 * @return 文本类型返回真，否则返回假。
	 * @since 1.0
	 */
	default boolean isText() {
		Class<?> clazz = getOriginClass();
		return CharSequence.class.isAssignableFrom(clazz) || char.class == clazz || Character.class == clazz;
	}

	/**
	 * 格式化为文本内容
	 * 
	 * @param value 被格式化值
	 * @return 格式化后文本
	 * @since 1.0
	 */
	default String format(T value) {
		return Objects.toString(value);
	}

	/**
	 * 格式化为文本内容
	 * 
	 * @param value     被格式化值
	 * @param nullValue 空值返回文本
	 * @return 格式化后文本
	 * @since 1.0
	 */
	default String format(T value, String nullValue) {
		return Objects.toString(value, nullValue);
	}

	/**
	 * 解析文本内容
	 * 
	 * @param text 文本内容
	 * @return 解析后数据
	 * @since 1.0
	 */
	T parse(String text);

	/**
	 * 解析文本内容
	 * 
	 * @param text      文本内容
	 * @param nullValue 空值文本
	 * @return 解析后数据
	 * @since 1.0
	 */
	default T parse(String text, String nullValue) {
		if (text == null || text.equals(nullValue)) {
			return null;
		}
		return parse(text);
	}

	/**
	 * 转换数据
	 * 
	 * @param value 被转换数据
	 * @return 转换后数据
	 * @since 1.0
	 */
	default T cast(Object value) {
		return cast(value, null, null);
	}

	/**
	 * 转换数据
	 * 
	 * @param value  被转换数据
	 * @param parser 文本解析器
	 * @return 转换后数据
	 * @since 1.0
	 */
	default T cast(Object value, Function<String, T> parser) {
		return cast(value, null, parser);
	}

	/**
	 * 转换数据
	 * 
	 * @param value     被转换数据
	 * @param nullValue 空值返回数据
	 * @param parser    文本解析器
	 * @return 转换后数据
	 * @since 1.0
	 */
	default T cast(Object value, T nullValue, Function<String, T> parser) {
		if (getOriginClass().isInstance(value)) {
			@SuppressWarnings("unchecked")
			T result = (T) value;
			if (isLegal(result)) {
				return result;
			}
			return null;
		} else if (value instanceof CharSequence) {
			if (parser != null) {
				return (T) parser.apply(value.toString());
			} else {
				return parse(value.toString());
			}
		} else {
			return null;
		}
	}

}
